﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace KnightShortestPath
{
    /// <summary>
    /// This class models a movement on a chessboard which has: a row and a column, a previous move (parent), 
    /// and an array of 8 possible movements. This class is defined as the node element in the tree of possible 
    /// movements to find the shortest path between two positions on a chessboard.
    /// </summary>
    public class Node
    {
        /// <summary>
        /// Represents a row in a chessboard
        /// </summary>
        private byte row;

        /// <summary>
        /// Represents a column in a chessboard
        /// </summary>
        private byte col;

        /// <summary>
        /// Represents the prevous movement of a piece on achessboard
        /// </summary>
        private Node parent;

        /// <summary>
        /// Represents the set of possible movements of a piece (for this case a knight) 
        /// on a chessboard
        /// </summary>
        private Node[] child;

        /// <summary>
        /// Creates a new instance of the <see cref="KnightShortestPath.Node"/> class.
        /// </summary>
        /// <param name='parent'>
        /// Parent: Previous position of a movement
        /// </param>
        /// <param name='row'>
        /// Row: Number of the row in the chess board starting in zero.
        /// </param>
        /// <param name='col'>
        /// Col: Number of the column in the chess board starting in zero.
        /// </param>
        public Node(Node parent, byte row, byte col)
        {
            this.parent = parent;
            this.row = row;
            this.col = col;
            this.child = new Node[8];
        }

        /// <summary>
        /// Creates a new instance of the <see cref="KnightShortestPath.Node"/> class.
        /// </summary>
        public Node() : this(null, 0, 0) { }

        /// <summary>
        /// Creates a new instance of the <see cref="KnightShortestPath.Node"/> class.
        /// </summary>
        /// <param name='row'>
        /// Row: Number of the row in the chess board starting in zero.
        /// </param>
        /// <param name='col'>
        /// Col: Number of the column in the chess board starting in zero.
        /// </param>
        public Node(byte row, byte col) : this(null, row, col) { }

        /// <summary>
        /// Creates a cloned copy of an instance of the <see cref="KnightShortestPath.Node"/> class
        /// </summary>
        /// <param name="copy">
        /// Copy: Instance of <see cref="KnightShortestPath.Node"/> which will be cloned.
        /// </param>
        public Node(Node copy) : this(null, copy.row, copy.col) 
        {
            for(int i=0; i<8; i++){
                if (copy.child[i] != null)
                {
                    this.child[i] = new Node(copy.child[i]);
                    this.child[i].parent = this;
                }
                
            }
        }

        /// <summary>
        /// Row Property: Gets or Sets the value of row.
        /// </summary>
        public byte Row
        {
            get { return row; }
            set { row = value; }
        }

        /// <summary>
        /// Column Property: Gets or Sets the value of column.
        /// </summary>
        public byte Col
        {
            get { return col; }
            set { col = value; }
        }

        /// <summary>
        /// Parent Property: Gets or Sets the value of parent.
        /// </summary>
        public Node Parent
        {
            get { return parent; }
            set { parent = value; }
        }

        /// <summary>
        /// Child Property: Gets or Sets the value of child.
        /// </summary>
        public Node[] Child
        {
            get { return child; }
            set { child = value; }
        } 
        
        /// <summary>
        /// Compares if two instances of the <see cref="KnightShortestPath.Node"/> class represents the same object.
        /// </summary>
        /// <param name="other">
        /// Other: instace of <see cref="KnightShortestPath.Node"/> which will be compared.
        /// </param>
        /// <returns>
        /// True if both instances are <see cref="KnightShortestPath.Node.Equivalent"/> and their 
        /// parents are also <see cref="KnightShortestPath.Node.Equivalent"/> otherwise False.
        /// </returns>
        public bool Equals(Node other){
            return (this.Equivalent(other) && this.parent.Equivalent(other.parent));
        }

        /// <summary>
        /// Compares if two instances of the <see cref="KnightShortestPath.Node"/> class represents the same place on the chess 
        /// board, that is: both are on the same row and column.
        /// </summary>
        /// <param name="node">
        /// Node: instace of <see cref="KnightShortestPath.Node"/> which will be compared.
        /// </param>
        /// <returns>
        /// True if both instances of <see cref="KnightShortestPath.Node"/> are placed in the same position, otherwise, False.
        /// </returns>
        public bool Equivalent(Node node) 
        {
            if(node == null){
                return false;
            }
            return this.row == node.row && this.col == node.col;
        }

        /// <summary>
        /// Evaluates if this instances of the <see cref="KnightShortestPath.Node"/> class has any instance setted in the 
        /// child's array
        /// </summary>
        /// <returns>
        /// True if any of the elements in the child's array is an instance of <see cref="KnightShortestPath.Node"/>, 
        /// otherwise, False.
        /// </returns>
        public bool HasAnyChild()
        {
            bool hasAnyChild = false;
            foreach (Node n in this.Child)
            {
                hasAnyChild |= (n != null);
            }
            return hasAnyChild;
        }

        /// <summary>
        /// Override <see cref="System.Object.ToString"/>
        /// </summary>
        /// <returns>
        /// A string that represents a <see cref="KnightShortestPath.Node"/> object
        /// </returns>
        public override String ToString() {
            String str = "Row: " + this.row + ",  Col: " + this.col;
            if (this.parent != null)
            {
                str += ", Parent[" + parent.row + "," + parent.col + "]";
            }
            return str;
        }
    }
}
